package com.geline.word.util;

import com.geline.word.constants.HtmlToWordConstants;
import fr.opensagres.poi.xwpf.converter.core.BasicURIResolver;
import fr.opensagres.poi.xwpf.converter.core.FileImageExtractor;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * 工具类
 * @author: mengxin
 * @date: 2022/10/18 17:01
 */
@Slf4j
public class Word2HtmlUtil {

    /**
     * docx转html 输出到资源/{fileDirPath}/{fileName}
     * @param file
     * @param rootPath
     * @param id
     * @throws IOException
     */
    public static File docxToHtml(MultipartFile file, String rootPath, String id) throws IOException {
        String wordDir = rootPath+"words/"+id;
        File rootDirFile = new File(wordDir+"/word/");
        if(!rootDirFile.exists()){
            rootDirFile.mkdirs();
        }
        String htmlFilePath = wordDir+"/index.html";
        File htmlFile = new File(htmlFilePath);
        if(!htmlFile.exists()){
            log.info("docxToHtml createNewFile = {}, {}", htmlFilePath, htmlFile.createNewFile());
        }

        XWPFDocument document = new XWPFDocument(file.getInputStream());
        XHTMLOptions options = XHTMLOptions.create();
        // 存放图片的文件夹
        options.setExtractor(new FileImageExtractor(new File(wordDir)));
        // html中图片的路径
        options.URIResolver(new BasicURIResolver("/words/"+id));
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(htmlFilePath), "utf-8");
        XHTMLConverter xhtmlConverter = (XHTMLConverter) XHTMLConverter.getInstance();
        xhtmlConverter.convert(document, writer, options);
        writer.close();
        return htmlFile;
    }

    /**
     * doc转html 输出到资源/{fileDirPath}/{htmlFileName}
     * @param file
     * @param rootPath
     * @param id
     * @throws TransformerException
     * @throws IOException
     * @throws ParserConfigurationException
     */
    public static File docToHtml(MultipartFile file, String rootPath, String id) throws TransformerException, IOException, ParserConfigurationException {
        String wordDir = rootPath+"words/"+id;
        File rootDirFile = new File(wordDir+"/word/");
        if(!rootDirFile.exists()){
            rootDirFile.mkdirs();
        }
        String htmlFilePath = wordDir+"/index.html";
        File htmlFile = new File(htmlFilePath);
        if(!htmlFile.exists()){
            log.info("docToHtml createNewFile = {}, {}", htmlFilePath, htmlFile.createNewFile());
        }

        HWPFDocument hwpfDocument = new HWPFDocument(file.getInputStream());
        WordToHtmlConverter converter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
        //设置存储图片的管理者--使用匿名内部类实现 该类实现了PicturesManager接口，实现了其中的savePicture方法
        converter.setPicturesManager(new PicturesManager() {
            FileOutputStream out = null;
            //在下面的processDocument方法内部会调用该方法 用于存储word中的图片文件
            @Override
            public String savePicture(byte[] bytes, PictureType pictureType, String name, float width, float height) {
                String imgName = String.valueOf(System.currentTimeMillis());
                try {
                    //单个图片的保存
                    out = new FileOutputStream(wordDir + "/image/" + imgName + ".jpg");
                    out.write(bytes);
                } catch (IOException exception) {
                    exception.printStackTrace();
                } finally {
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //这里要返回给操作者（HtmlDocumentFacade）一个存储的路径 用于生成Html时定位到图片资源
                return imgName + ".jpg";
            }
        });
        //使用外观模式，将hwpfDocument文档对象设置给HtmlDocumentFacade中的Document属性
        converter.processDocument(hwpfDocument);
        //获取转换器中的document文档
        Document htmlDocument = converter.getDocument();
        //充当文档对象模型 （DOM） 树形式的转换源树的持有者  -- 源树
        DOMSource domSource = new DOMSource(htmlDocument);
        //转换器 该对象用于将源树转换为结果树
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        //设置输出时的以什么方式输出，也可说是结果树的文件类型 可以是html/xml/text或者是一些扩展前三者的扩展类型
        transformer.setOutputProperty(OutputKeys.METHOD, "html");
        //设置一些必要的属性 设置输出时候的编码为utf-8
        transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
        //转换 将输入的源树转换为结果树并且输出到streamResult中
        transformer.transform(domSource, new StreamResult(htmlFile));
        return htmlFile;
    }

    /**
     * 将html中src的相对路径增加服务器资源前缀
     *
     * @param htmlBody
     * @return
     */
    public static String replaceImgSrc(String urlHeader, String htmlBody) {
        org.jsoup.nodes.Document document = Jsoup.parse(htmlBody);
        Elements nodes = document.select("img");
        int nodeLenth = nodes.size();
        for (int i = 0; i < nodeLenth; i++) {
            Element e = nodes.get(i);
            String src = e.attr("src");
            if (StringUtils.isNotBlank(src)) {
                e.attr("src", urlHeader + src);
            }
        }
        if (htmlBody.contains(HtmlToWordConstants.HTML_ELEMENT)) {
            return document.toString();
        } else {
            return document.select("body>*").toString();
        }
    }
}
